Orientados a la comunicación e interacción entre objetos y el control de flujo del proceso.
Los patrones de comportamiento tienen que ver con diferentes aspectos:
Algoritmos.
Asignación de responsabilidades.
Comunicación entre objetos.
El patrón command tiene como objetivo encapsular en un objeto cada función. como sustituto de otro para controlar el acceso del mismo. De esta forma se puede parametrizar a los clientes con diferentes peticiones, incluir las peticiones en una cola o incluso llevar un registro de las peticiones efectuadas y poder hacer así las operaciones.
Ejemplo:
Un mando de control remoto que permita controlar todos los dispositivos controlables de una casa: aire acondicionado, calefacción, televisión, luces, persianas, alarma, etc.
El mando de control remoto también debe permitir incorporar en el futuro nuevos dispositivos.
Se dispone de un conjunto de clases, una por cada dispositivo controlable. Cada clase tiene métodos para operar directamente con el dispositivo.
![]() |
|---|
Observando las distintas clases de los dispositivos, se ve que cada una tiene una interfaz distinta.
Sin embargo, las funciones que se pueden asociar a los distintos botones del mando tienen una forma común.
Cada función tiene:
Un receptor concreto.
Una acción concreta sobre el receptor.

Debemos utilizar este patrón cuando:
Es necesario realizar peticiones a objetos pero no se conoce nada de la operación a realizar o el receptor de dicha petición no es conocido.
Para parametrizar objetos con operaciones.
Para poner operaciones en cola, programar su ejecución, o ejecutarlas de forma remota.
Para implementar operaciones reversibles (deshacer).
Ventajas e inconvenientes del patrón Adapter:
Ventajas:
Principio de responsabilidad única. Puedes desacoplar las clases que invocan operaciones de las que realizan esas operaciones.
Principio de abierto/cerrado. Puedes introducir nuevos comandos en la aplicación sin descomponer el código cliente existente.
Puedes implementar deshacer/rehacer.
Puedes implementar la ejecución diferida de operaciones.
Puedes ensamblar un grupo de comandos simples para crear uno complejo.
Inconvenientes:
El código puede complicarse, ya que estás introduciendo una nueva capa entre emisores y receptores.


xxxxxxxxxx141public class Alarma {2 3 public Alarma() { 4 System.out.println("Creado el objeto ALARMA");5 }6 7 public void activar() { 8 System.out.println("Alarma activada");9 }10 11 public void desactivar() { 12 System.out.println("Alarma desactivada");13 }14}xxxxxxxxxx341public class Calefaccion {2 3 private int temperaturaActual;4
5 public Calefaccion() {6 System.out.println("Creado el objeto CALEFACCION"); 7 }8 9 public void encender() {10 System.out.println("Encender calefaccion"); 11 }12 13 public void apagar() { 14 System.out.println("Apagar calefaccion");15 }16 17 public void bajar() { 18 System.out.println("Bajar calefaccion");19 }20 21 public void subir() { 22 System.out.println("Subir calefaccion");23 }24 25 public void fijarTemperatura(int temp) {26 27 temperaturaActual = temp; 28 System.out.println("Se fija la temperatura de la calefaccionn a " + temp);29 }30 31 public int temperaturaActual() { 32 return temperaturaActual;33 } 34}
xxxxxxxxxx41public interface Orden {2 3 public void ejecutar();4}
xxxxxxxxxx121public class ActivarAlarma implements Orden {2 3 private Alarma alarma;4 5 public ActivarAlarma(Alarma alarma) {6 this.alarma = alarma; 7 }8
9 public void ejecutar() {10 alarma.activar();11 }12}xxxxxxxxxx121public class DesactivarAlarma implements Orden {2
3 private Alarma alarma;4 5 public DesactivarAlarma(Alarma alarma) {6 this.alarma = alarma; 7 }8
9 public void ejecutar() {10 alarma.desactivar();11 }12}xxxxxxxxxx121public class EncenderCalefaccion implements Orden {2
3 private Calefaccion calefaccion;4 5 public EncenderCalefaccion(Calefaccion calefaccion) { 6 this.calefaccion = calefaccion;7 }8 9 public void ejecutar() { 10 calefaccion.encender();11 }12}xxxxxxxxxx121public class ApagarCalefaccion implements Orden {2
3 private Calefaccion calefaccion;4 5 public ApagarCalefaccion(Calefaccion calefaccion) { 6 this.calefaccion = calefaccion;7 }8 9 public void ejecutar() { 10 calefaccion.apagar();11 }12}xxxxxxxxxx121public class SubirCalefaccion implements Orden {2 3 private Calefaccion calefaccion;4 5 public SubirCalefaccion(Calefaccion calefaccion) { 6 this.calefaccion = calefaccion;7 }8 9 public void ejecutar() { 10 calefaccion.subir();11 }12}xxxxxxxxxx121public class BajarCalefaccion implements Orden {2 3 private Calefaccion calefaccion;4 5 public BajarCalefaccion(Calefaccion calefaccion) { 6 this.calefaccion = calefaccion;7 }8 9 public void ejecutar() { 10 calefaccion.bajar();11 }12}
xxxxxxxxxx161public class Boton {2 3 Orden orden;4
5 public Boton(Orden orden) { 6 this.orden = orden; 7 }8 9 public void setOrden(Orden orden) { 10 this.orden = orden; 11 }12 13 public void ejecutarOrden () { 14 orden.ejecutar(); 15 }16}
xxxxxxxxxx781public class Cliente {2 3 private ArrayList <Boton> botones; 4 private Calefaccion calefaccion;5 private Alarma alarma;6
7 public Cliente() {8 9 // Crear los dispositivos (receptores) 10 System.out.println("========= CREACION DE DISPOSITIVOS =========="); 11 12 calefaccion = new Calefaccion();13 alarma = new Alarma();14 botones = new ArrayList<Boton>(); 15 } 16 17 public void configurar_1() {18
19 botones.clear();20 21 Orden encenderCalefaccion = new EncenderCalefaccion(calefaccion); // Crear la orden pasándole el receptor 22 botones.add(new Boton(encenderCalefaccion)); // Crear el invocador y asociarlo con su orden23 24 Orden subirCalefaccion = new SubirCalefaccion(calefaccion); 25 botones.add(new Boton(subirCalefaccion)); 26 27 Orden activarAlarma = new ActivarAlarma(alarma); 28 botones.add(new Boton(activarAlarma)); 29 }30 31 public void configurar_2() {32 33 botones.clear();34 35 Orden apagarCalefaccion = new ApagarCalefaccion(calefaccion); // Crear la orden pasándole el receptor 36 botones.add(new Boton(apagarCalefaccion)); // Crear el invocador y asociarlo con su orden 37 38 Orden desactivarAlarma = new DesactivarAlarma(alarma); 39 botones.add(new Boton(desactivarAlarma)); 40 }41 42 public void configurar_3() {43 44 botones.clear();45 46 Orden encenderCalefaccion = new EncenderCalefaccion(calefaccion); // Crear la orden pasándole el receptor 47 botones.add(new Boton(encenderCalefaccion)); // Crear el invocador y asociarlo con su orden48
49 Orden ponerCalefaccionA = new PonerCalefaccionA(calefaccion); 50 botones.add(new Boton(ponerCalefaccionA)); 51 } 52 53 public void operar() {54
55 for (Boton boton:botones) { 56 boton.ejecutarOrden(); 57 } 58} 59
60 public static void main(String[] args) {61 62 Cliente cliente = new Cliente();63 64 System.out.println("====> Inicio configuracion 1"); 65 cliente.configurar_1(); 66 cliente.operar();67 68 System.out.println("====> Inicio configuracion 2"); 69 cliente.configurar_2();70 cliente.operar();71
72 System.out.println("====> Inicio configuracion 3"); 73 cliente.configurar_3(); 74 cliente.operar();75
76 System.out.println("====> Fin de sistema"); 77 }78}
Para comprender este patrón es necesario conocer el concepto de gramática formal.
Una gramática es un conjunto de reglas que define un lenguaje concreto (se llaman reglas de derivación).
Por ejemplo, un lenguaje para escribir expresiones lógicas del tipo 0 AND 1, 1 OR (0 AND 1), etc, puede definirse con la siguiente gramática:
| exp = exp op exp exp = booleano booleano = 0 op = ADN exp = booleano booleano = 1 | ![]() |
|---|
Cada nodo interno con su(s) nodo(s) hijo(s) corresponde a una regla de la gramática.
Las hojas del árbol son los símbolos terminales de la gramática. (Un sentencia del lenguaje sólo contiene símbolos terminales).
Los nodos internos del árbol son los símbolos no terminales de la gramática.
El árbol de análisis de la expresión 1 OR (0 AND 1) sería:
.png)
El patrón interpreter, dado un lenguaje simple, define una representación de su gramática junto con un intérprete que utiliza dicha representación para interpretar sentencias del lenguaje.
Se parte de una gramática que define un lenguaje simple.
El patrón define cómo se representa dicha gramática (define las clases necesarias para los símbolos terminales y no terminales).
El patrón define el mecanismo que permite interpretar sentencias del lenguaje.
Interpretar una sentencia significa “hacer algo” con la sentencia.
Ejemplo:
Una sentencia booleana:
Se puede evaluar: “interpretar” = “evaluar”
Se puede traducir a otro lenguaje: “interpretar” = “traducir”
El uso de este patrón no se limita solamente a la interpretación de expresiones booleanas o aritméticas.
Se puede utilizar en todos los casos en los que se pueda expresar un problema mediante una gramática.
Por ejemplo, se puede utilizar en una aplicación que trabaje con fórmulas químicas. Se puede considerar que interpretar una fórmula química consiste en calcular su masa molecular.
También se podría usar este patrón en una aplicación de gestión de menús de comida. Los menús serían las sentencias del lenguaje. Interpretar un menú podría ser validar si es equilibrado. El contexto podría almacenar información de los distintos platos.
Ventajas e inconvenientes del patrón Adapter:
Ventajas:
Se puede incrementar fácilmente la gramática.
Es fácil implementar la gramática. Las clases son pequeñas y algunas de ellas parecidas.
La misma gramática con distintas implementaciones del intérprete proporcionan funcionalidades diferentes.
Inconvenientes:
No es adecuado para gramáticas complejas.
Exige conocimientos de diseño de gramáticas.
Es necesario que un agente externo construya el árbol de análisis.


xxxxxxxxxx31public interface ExpresionAbstracta { 2 public String interpretar();3}
xxxxxxxxxx121public class ExpresionTerminal implements ExpresionAbstracta {2 3 String terminal;4
5 public ExpresionTerminal(String terminal) { 6 this.terminal = terminal; 7 }8
9 public String interpretar() { 10 return terminal;11 }12}
xxxxxxxxxx121public class BooleanoCero implements ExpresionAbstracta {2 3 ExpresionAbstracta terminal;4
5 public BooleanoCero(ExpresionAbstracta terminal) { 6 this.terminal = terminal; 7 }8
9 public String interpretar() { 10 return terminal.interpretar(); 11 }12}xxxxxxxxxx121public class BooleanoUno implements ExpresionAbstracta {2 3 ExpresionAbstracta terminal;4
5 public BooleanoUno(ExpresionAbstracta terminal) { 6 this.terminal = terminal; 7 }8
9 public String interpretar() { 10 return terminal.interpretar(); 11 }12}xxxxxxxxxx121public class OperadorAND implements ExpresionAbstracta {2
3 ExpresionAbstracta terminal;4
5 public OperadorAND(ExpresionAbstracta terminal) { 6 this.terminal = terminal;7 }8
9 public String interpretar() { 10 return terminal.interpretar(); 11 }12}xxxxxxxxxx121public class OperadorOR implements ExpresionAbstracta {2
3 ExpresionAbstracta terminal;4
5 public OperadorOR(ExpresionAbstracta terminal) { 6 this.terminal = terminal;7 }8
9 public String interpretar() { 10 return terminal.interpretar(); 11 }12}xxxxxxxxxx121public class ParentesisIzq implements ExpresionAbstracta {2 3 ExpresionAbstracta terminal;4
5 public ParentesisIzq(ExpresionAbstracta terminal) { 6 this.terminal = terminal;7 }8
9 public String interpretar() { 10 return terminal.interpretar(); 11 }12}xxxxxxxxxx121public class ParentesisDch implements ExpresionAbstracta {2 3 ExpresionAbstracta terminal;4
5 public ParentesisDch(ExpresionAbstracta terminal) { 6 this.terminal = terminal;7 }8
9 public String interpretar() { 10 return terminal.interpretar(); 11 }12}
xxxxxxxxxx471public class Operacion implements ExpresionAbstracta {2 3 ExpresionAbstracta exp1;4 ExpresionAbstracta op1;5 ExpresionAbstracta parl;6 ExpresionAbstracta exp2;7 ExpresionAbstracta op2;8 ExpresionAbstracta exp3;9 ExpresionAbstracta pard;10 11 public Operacion(ExpresionAbstracta exp1, ExpresionAbstracta op1, ExpresionAbstracta parl, ExpresionAbstracta exp2, ExpresionAbstracta op2, ExpresionAbstracta exp3, ExpresionAbstracta pard) {12 13 this.exp1 = exp1; 14 this.op1 = op1; 15 this.parl = parl;16 this.exp2 = exp2; 17 this.op2 = op2; 18 this.exp3 = exp3;19 this.pard = pard; 20 }21
22 public String interpretar() {23 24 boolean boolean1 = exp1.interpretar().equals("1") ? true : false; 25 boolean boolean2 = exp2.interpretar().equals("1") ? true : false; 26 boolean boolean3 = exp3.interpretar().equals("1") ? true : false; 27 boolean resultado1; 28 boolean resultado2; 29 String operador1 = op1.interpretar();30 String operador2 = op2.interpretar();31 32 if (operador2.equals("AND")) 33 resultado1 = boolean2 && boolean3; 34 else 35 resultado1 = boolean2 || boolean3;36 37 if (operador1.equals("AND")) 38 resultado2 = boolean1 && resultado1; 39 else 40 resultado2 = boolean1 || resultado1;41 42 if (resultado2) 43 return "1"; 44 else 45 return "0"; 46 }47}
xxxxxxxxxx241public class Cliente {2 3 public static void main(String[] args) {4 5 // CONSTRUIR EL ÁRBOL DE ANÁLISIS SINTÁCTICO DE LA CADENA "0 OR (0 AND 1)" 6 ExpresionAbstracta cero = new ExpresionTerminal("0");7 ExpresionAbstracta booleanoCero = new BooleanoCero(cero);8 ExpresionAbstracta or = new ExpresionTerminal("OR");9 ExpresionAbstracta operadorOR = new OperadorOR(or);10 ExpresionAbstracta parI = new ExpresionTerminal("parI");11 ExpresionAbstracta operadorParI = new ParentesisIzq(parI);12 //Aqui no ponemos el cero porque esta instanciado arriba13 ExpresionAbstracta and = new ExpresionTerminal("AND");14 ExpresionAbstracta operadorAND = new OperadorAND(and);15 ExpresionAbstracta uno = new ExpresionTerminal("1");16 ExpresionAbstracta booleanoUno = new BooleanoUno(uno);17 ExpresionAbstracta parD = new ExpresionTerminal("parD");18 ExpresionAbstracta operadorParD = new ParentesisDch(parD);19 20 ExpresionAbstracta expresion = new Operacion(booleanoCero, operadorOR, operadorParI, booleanoCero, operadorAND, booleanoUno, operadorParD); 21 22 System.out.println("RESULTADO EXPRESIÓN 3 = " + expresion.interpretar()); 23 }24}
El patrón observador proporciona un mecanismo para que los cambios de estado de un objeto sean notificados a otros objetos que previamente se han registrado para ello.

Define una relación uno a muchos entre un conjunto de objetos.
Cuando el estado de un objeto cambia, los objetos dependientes son notificados.

Ejemplo:
Un hospital que muestra por pantalla la evolución de los procesos de los pacientes en quirófano.
Las pantallas de los aeropuertos que indican las puertas de embarque.
Aplicación que muestra en dos ventanas diferentes los datos meteorológicos de temperatura, humedad y presión que se recogen de unos sensores cada cierto intervalo de tiempo. Con esa misma frecuencia, se deben actualizar las dos ventanas que muestran los datos. Una de ellas muestra los datos actuales de las tres variables, y la otra los valores máximos y mínimos de dos de ellas. En un futuro se prevé que habrá nuevas ventanas.

Hay dos modelos para transmitir la información del cambio de estado del sujeto:
Modelo push: el sujeto envía a los observadores toda la información detallada del cambio (la necesiten o no).
Modelo pull: el sujeto solo envía a los observadores un aviso de que ha ocurrido un cambio de estado y los observadores piden los datos que necesiten.
El modelo pull respeta el principio abierto/cerrado. Si se amplía el estado del sujeto por exigencias de incorporación de nuevos observadores, no es necesaria la modificación de observadores antiguos, mientras que en el modelo push sí lo sería.
Si la relación de dependencia entre sujetos y observadores es compleja, puede ser necesario un objeto (Gestor) que mantenga dichas relaciones.

Hace corresponder a cada sujeto con sus observadores.
Define una estrategia de actualización.
Actualiza todos los observadores dependientes a petición de un sujeto.
Ventajas e inconvenientes del patrón Observador:
Ventajas:
Bajo acoplamiento entre el sujeto y los observadores. El sujeto tiene una lista de observadores sin conocer sus clases concretas.
El bajo acoplamiento permite reutilizar sujetos y observadores de manera independiente.
Comunicación mediante difusión, lo que permite añadir/eliminar observadores fácilmente.
Inconvenientes:
Los observadores son notificados en un orden aleatorio.


xxxxxxxxxx61public interface Sujeto {2 3 public void registrarObservador(Observador o);4 public void borrarObservador(Observador o);5 public void notificar();6}xxxxxxxxxx41public interface Observador {2 3 public void actualizar(double temperatura, double humedad, double presion);4}
xxxxxxxxxx461public class DatosMeteorologicos implements Sujeto {2 3 /* ESTE ES EL SUJETO CONCRETO */ 4 private ArrayList<Observador> observadores; 5 private double temperatura;6 private double humedad;7 private double presion;8
9 public DatosMeteorologicos() { 10 observadores = new ArrayList<Observador>(); 11 }12 13 public void registrarObservador(Observador o) {14 15 observadores.add(o); 16 System.out.println("Registrado observador"); 17 }18 19 public void borrarObservador(Observador o) {20
21 observadores.remove(o);22 }23 24 /* LA IMPLEMENTACIÓN DEL MÉTODO DE LA INTERFAZ (notificar()) , EN ESTA OCASIÓN, ESTÁ EN EL SUJETO CONCRETO */25 public void notificar() {26 System.out.println("Notificando ...");27 28 for (Observador o:observadores) { 29 o.actualizar(); 30 } 31 }32 33 public void cambioCondicionesMeteorologicas() {34 notificar(); 35 }36 37 /* ÉSTE ES EL MÉTODO DEL SUJETO CONCRETO PARA ESTABLECER EL ESTADO UNA VEZ QUE RECIBE CAMBIOS EN LAS CONDICIONES (SIMULADO) */ 38 public void establecerEstado(double temperatura, double humedad, double presion) {39 40 this.temperatura = temperatura; 41 this.humedad = humedad; 42 this.presion = presion;43 44 cambioCondicionesMeteorologicas(); 45 }46}
xxxxxxxxxx341public class DatosActuales implements Observador {2 3 /* DADO QUE EL ESTADO EN EL OBSERVADOR GENERAL (INTERFAZ) ESTÁ DISGREGADO, EN LOS CONCRETOS TAMBIÉN LO PUEDE ESTAR */4 private double temperatura;5 private double humedad;6 private double presion;7
8 /* ÉSTE ES EL SUJETO, NECESARIO PARA REGISTRARSE COMO OBSERVADOR */9 private DatosMeteorologicos datos;10
11 public DatosActuales(DatosMeteorologicos datos) {12 13 /* EN EL CONSTRUCTOR SE LE ASIGNA EL SUJETO AL QUE VA A OBSERVAR */14 this.datos = datos;15 /* Y SE REGISTRA COMO OBSERVADOR */16 datos.registrarObservador(this);17 }18
19 public void actualizar(double temperatura, double humedad, double presion) {20 21 /* REESCRITURA DEL MÉTODO DE LA INTERFAZ */ 22 /* ACTUALIZA EL ESTADO COMO NECESITE */ 23 this.temperatura = temperatura; 24 this.humedad = humedad; 25 this.presion = presion;26
27 /* Y MUESTRA LOS DATOS COMO NECESITE */28 mostrarDatos();29 }30 31 public void mostrarDatos() {32 System.out.println("CONDICIONES ACTUALES: " + temperatura + "°C, " + humedad + "%, " + presion + " kPa"); 33 }34}xxxxxxxxxx491public class Estadisticas implements Observador {2 3 /* ESTADO PUEDE TRANSFORMARSE EN LOS OBSERVADORES CONCRETOS EN LO QUE NECESITEN. 4 * ESTE OBSERVADOR CALCULA ESTADÍSTICAS CON CADA DATO NUEVO5 * POR LO TANTO NECESITA ESTA MANERA DE GUARDAR EL ESTADO */6 private double temperaturaMaxima = Double.NEGATIVE_INFINITY;7 private double humedadMaxima = Double.NEGATIVE_INFINITY;8 private double temperaturaMinima = Double.POSITIVE_INFINITY;9 private double humedadMinima = Double.POSITIVE_INFINITY;10 11 /* ÉSTE ES EL SUJETO, NECESARIO PARA REGISTRARSE COMO OBSERVADOR */12 DatosMeteorologicos datos;13
14 public Estadisticas(DatosMeteorologicos datos) {15 16 /* EN EL CONSTRUCTOR SE LE ASIGNA EL SUJETO AL QUE VA A OBSERVAR */17 this.datos = datos;18 /* Y SE REGISTRA COMO OBSERVADOR */19 datos.registrarObservador(this);20 }21
22 public void actualizar(double temperatura, double humedad, double presion) {23 24 /* REESCRITURA DEL MÉTODO DE LA INTERFAZ */25 /* ACTUALIZA EL ESTADO COMO NECESITE, EN ESTE CASO ACTUALIZACIÓN DE LAS ESTADÍSTICAS */26 if (temperatura < temperaturaMinima) 27 temperaturaMinima = temperatura;28 29 if (temperatura > temperaturaMaxima) 30 temperaturaMaxima = temperatura;31
32 if (humedad < humedadMinima) 33 humedadMinima = humedad;34
35 if (humedad > humedadMaxima) 36 humedadMaxima = humedad;37
38 /* Y MUESTRA LOS DATOS COMO NECESITE */ 39 mostrarDatos();40 }41 42 public void mostrarDatos() {43 44 System.out.println("Temperatura máxima: " + temperaturaMaxima + "°");45 System.out.println("Temperatura mínima: " + temperaturaMinima + "°");46 System.out.println("Humedad máxima: " + humedadMaxima + "%");47 System.out.println("Humedad mínima: " + humedadMinima + "%"); 48 }49}xxxxxxxxxx241public class AvisoHelada implements Observador {2 3 private double temperatura;4 5 private DatosMeteorologicos datos;6
7 public AvisoHelada(DatosMeteorologicos datos) {8 9 this.datos = datos;10 datos.registrarObservador(this);11 }12
13 public void actualizar(double temperatura, double humedad, double presion) {14 15 this.temperatura = temperatura;16 mostrarDatos();17 }18 19 public void mostrarDatos() { 20 21 if (temperatura < 0) 22 System.out.println("**** AVISO DE HELADA ******"); 23 }24}
xxxxxxxxxx201public class Cliente {2 3 public Cliente() {4 }5
6 public static void main(String[] args) {7 8 DatosMeteorologicos datos = new DatosMeteorologicos();9
10 Observador datosActuales = new DatosActuales(datos);11 Observador estadisticas = new Estadisticas(datos);12 Observador avisoHelada = new AvisoHelada(datos);13
14 datos.establecerEstado(25, 70, 100);15 datos.establecerEstado(23, 65, 101);16 datos.establecerEstado(20, 60, 102);17 datos.establecerEstado(19, 80, 103);18 datos.establecerEstado(-1, 80, 103);19 }20}

xxxxxxxxxx61public interface Sujeto {2 3 public void registrarObservador(Observador o);4 public void borrarObservador(Observador o);5 public void notificar();6}xxxxxxxxxx41public interface Observador {2 3 public void actualizar(double temperatura, double humedad, double presion);4}
xxxxxxxxxx611public class DatosMeteorologicos implements Sujeto { 2 3 /* ESTE ES EL SUJETO CONCRETO */ 4
5 /* OBS.- LA COLECCIÓN DE OBSERVADORES, EN ESTA OCASIÓN, ESTÁ EN EL SUJETO CONCRETO. */ 6 private ArrayList<Observador> observadores;7
8 /* EL ESTADO, EN ESTA OCASIÓN, SON INFORMACIONES SEPARADAS */ 9 private double temperatura;10 private double humedad;11 private double presion;12 13 public DatosMeteorologicos() { 14 observadores = new ArrayList<Observador>(); 15 }16 17 public double getTemperatura() {18 return temperatura;19 }20
21 public double getHumedad() {22 return humedad;23 }24
25 public double getPresion() {26 return presion;27 }28 29 public void registrarObservador(Observador o) {30
31 observadores.add(o); 32 System.out.println("Registrado observador"); 33 }34 35 public void borrarObservador(Observador o) {36 observadores.remove(o);37 }38 39 /* LA IMPLEMENTACIÓN DEL MÉTODO DE LA INTERFAZ (notificar()) , EN ESTA OCASIÓN, ESTÁ EN EL SUJETO CONCRETO */40 public void notificar() {41 System.out.println("Notificando ...");42 43 for (Observador o:observadores) { 44 o.actualizar(temperatura,humedad,presion); 45 } 46 }47 48 public void cambioCondicionesMeteorologicas() {49 notificar(); 50 }51 52 /* ÉSTE ES EL MÉTODO DEL SUJETO CONCRETO PARA ESTABLECER EL ESTADO UNA VEZ QUE RECIBE CAMBIOS EN LAS CONDICIONES (SIMULADO) */ 53 public void establecerEstado(double temperatura, double humedad, double presion) {54 55 this.temperatura = temperatura; 56 this.humedad = humedad; 57 this.presion = presion;58
59 cambioCondicionesMeteorologicas(); 60 }61}
xxxxxxxxxx351public class DatosActuales implements Observador {2 3 /* DADO QUE EL ESTADO EN EL OBSERVADOR GENERAL (INTERFAZ) ESTÁ DISGREGADO, EN LOS CONCRETOS TAMBIÉN LO PUEDE ESTAR */4 private double temperatura;5 private double humedad;6 private double presion;7 8 /* ÉSTE ES EL SUJETO, NECESARIO PARA REGISTRARSE COMO OBSERVADOR */9 private DatosMeteorologicos datos;10
11 public DatosActuales(DatosMeteorologicos datos) {12 13 /* EN EL CONSTRUCTOR SE LE ASIGNA EL SUJETO AL QUE VA A OBSERVAR */14 this.datos = datos;15 /* Y SE REGISTRA COMO OBSERVADOR */16 datos.registrarObservador(this);17 }18
19 public void actualizar() {20 21 /* REESCRITURA DEL MÉTODO DE LA INTERFAZ */ 22 /* ACTUALIZA EL ESTADO COMO NECESITE */ 23 temperatura = datos.getTemperatura(); 24 humedad = datos.getHumedad(); 25 presion = datos.getPresion();26
27 /* Y MUESTRA LOS DATOS COMO NECESITE */28 mostrarDatos();29 }30 31 public void mostrarDatos() {32 33 System.out.println("CONDICIONES ACTUALES: " + temperatura + "°C, " + humedad + "%, " + presion + " kPa"); 34 }35}xxxxxxxxxx511public class Estadisticas implements Observador {2 3 /* ESTADO PUEDE TRANSFORMARSE EN LOS OBSERVADORES CONCRETOS EN LO QUE NECESITEN. 4 * ESTE OBSERVADOR CALCULA ESTADÍSTICAS CON CADA DATO NUEVO5 * POR LO TANTO NECESITA ESTA MANERA DE GUARDAR EL ESTADO */6 private double temperaturaMaxima = Double.NEGATIVE_INFINITY;7 private double humedadMaxima = Double.NEGATIVE_INFINITY;8 private double temperaturaMinima = Double.POSITIVE_INFINITY;9 private double humedadMinima = Double.POSITIVE_INFINITY;10 11 /* ÉSTE ES EL SUJETO, NECESARIO PARA REGISTRARSE COMO OBSERVADOR */12 DatosMeteorologicos datos;13
14 public Estadisticas(DatosMeteorologicos datos) {15 16 /* EN EL CONSTRUCTOR SE LE ASIGNA EL SUJETO AL QUE VA A OBSERVAR */17 this.datos = datos;18 /* Y SE REGISTRA COMO OBSERVADOR */19 datos.registrarObservador(this);20 }21
22 public void actualizar() {23 24 double temperatura = datos.getTemperatura();25 double humedad = datos.getHumedad();26 /* REESCRITURA DEL MÉTODO DE LA INTERFAZ */27 /* ACTUALIZA EL ESTADO COMO NECESITE, EN ESTE CASO ACTUALIZACIÓN DE LAS ESTADÍSTICAS */28 if (temperatura < temperaturaMinima) 29 temperaturaMinima = temperatura;30
31 if (temperatura > temperaturaMaxima) 32 temperaturaMaxima = temperatura;33
34 if (humedad < humedadMinima) 35 humedadMinima = humedad;36
37 if (humedad > humedadMaxima) 38 humedadMaxima = humedad;39
40 /* Y MUESTRA LOS DATOS COMO NECESITE */ 41 mostrarDatos();42 }43 44 public void mostrarDatos() {45 46 System.out.println("Temperatura máxima: " + temperaturaMaxima + "°");47 System.out.println("Temperatura mínima: " + temperaturaMinima + "°");48 System.out.println("Humedad máxima: " + humedadMaxima + "%");49 System.out.println("Humedad mínima: " + humedadMinima + "%"); 50 }51}xxxxxxxxxx241public class AvisoHelada implements Observador {2 3 private double temperatura;4 5 private DatosMeteorologicos datos;6
7 public AvisoHelada(DatosMeteorologicos datos) {8 9 this.datos = datos;10 datos.registrarObservador(this);11 }12
13 public void actualizar() {14 15 temperatura = datos.getTemperatura();16 mostrarDatos();17 }18 19 public void mostrarDatos() { 20 21 if (temperatura < 0) 22 System.out.println("****** AVISO DE HELADA ******"); 23 }24}
xxxxxxxxxx201public class Cliente {2 3 public Cliente() {4 }5
6 public static void main(String[] args) {7 8 DatosMeteorologicos datos = new DatosMeteorologicos();9
10 Observador datosActuales = new DatosActuales(datos);11 Observador estadisticas = new Estadisticas(datos);12 Observador avisoHelada = new AvisoHelada(datos);13
14 datos.establecerEstado(25, 70, 100);15 datos.establecerEstado(23, 65, 101);16 datos.establecerEstado(20, 60, 102);17 datos.establecerEstado(19, 80, 103);18 datos.establecerEstado(-1, 80, 103);19 }20}